#pragma once
// #include"../instruction_module/instruction.h"
// class SPU;
#include"../Global.h"
#include<vector>
#include<map>
#include"write_delay_control/write_delay_control.h"
#include"../hardware_resource/VPU/VPU.h"
#include"../hardware_resource/SPU/SPU.h"
#include"../instruction_module/instruction_mem.h"

class Engine {
public:
    Engine(addr_size_t start_addr, V_memory* am, memory* sm, memory* gsm, RegisterFile* rf, VPU* vpu_, SPU* spu_) : vpu(vpu_), spu(spu_) {
        // instr_buffer = new std::vector<instruction*>(8);
        instr_buffer = new std::vector<instruction*>();
        instr_buffer->reserve(8);
        PC = start_addr; //start_addr为指令解析阶段分析得到的整个程序入口
        WCM = new WriteControlModule(am, sm, gsm, rf);
    }
    Engine(addr_size_t start_addr, V_memory* am, memory* sm, memory* gsm, RegisterFile* rf, Instruction_Mem* instr_mem) {
        // instr_buffer = new std::vector<instruction*>(8);
        instr_buffer = new std::vector<instruction*>();
        instr_buffer->reserve(8);
        PC = start_addr; //start_addr为指令解析阶段分析得到的整个程序入口
        WCM = new WriteControlModule(am, sm, gsm, rf);
        instr_memory = instr_mem;
        resume_clock = -2;
    }
    ~Engine() {
        delete instr_buffer;
        delete WCM;
    }
    //步进操作，时钟周期+1，执行该周期内的相应所有操作
    bool Stepping();
    //TODO: 考虑后续提供一个快速步进的方法，可以一次推进多个周期（在这些周期内保证逻辑是足够简单的）
    WriteControlModule* getWCM() {
        return this->WCM;
    }
    bool StopNCycles(int cycles);
    bool Stop();
    bool Resume();
    //用于跳转指令设置跳转的目的地址
    void set_PC(addr_size_t new_PC) {
        this->PC = new_PC;
    }
    void set_End_PC(addr_size_t new_End_PC) {
        this->End_PC = new_End_PC;
    }   
    void set_vpu(VPU* vpu) {
        this->vpu = vpu;
    }
    void set_spu(SPU* spu) {
        this->spu = spu;
    }
    

private:
    //TODO:后续将取指功能外移到外层控制模块，该控制模块仅接收分配的指令，进行单个DSP内部的执行控制
    addr_size_t Fetching(addr_size_t addr);
    void ClearInstrBuffer();
    bool InstrDistribution(instruction* instr);
    

    //引擎内部保存的指令缓冲区，Fetching函数执行后将读取出的指令存入该buffer中
    //!由于dsp每一周期都进行指令的发射和执行，延迟和流水线在硬件部件内部实现，因此engine内部无需处理延迟
    std::vector<instruction*> *instr_buffer;
    // global_clock_t global_clock; //在执行引擎中存储模拟的当前时钟周期，设置为private类型，减少bug发生的可能性
    addr_size_t PC; //PC指针，用于存储下一条要执行的指令地址
    addr_size_t End_PC; //End_PC指针，用于存储整个函数或程序的结束地址
    WriteControlModule* WCM;
    global_clock_t resume_clock; //用于标识在哪个周期中恢复指令派发
    VPU*    vpu;
    SPU*    spu;
    Instruction_Mem* instr_memory;
};

class GroupEngine {
public:
    GroupEngine() {
        node_engines = new std::vector<Engine*>();
        node_engines->reserve(4); //每个线程组包含4个DSP核
    }
    ~GroupEngine() {
        delete node_engines;
    }
    bool Stepping();
    void add_node_engine(Engine* engine);
    bool Execute(); //需要提供一个Execute函数，进行多周期的连续执行
private:
    std::vector<Engine*>* node_engines;
};

class ClusterEngine {
public:
    ClusterEngine() {
        group_engines = new std::map<int, GroupEngine*>();
    }
    ~ClusterEngine() {
        delete group_engines;
    }
    // bool Stepping();
    void add_group_engine(int thread_id, GroupEngine* engine);
    // bool Execute(); //需要提供一个Execute函数，进行多周期的连续执行
    GroupEngine* get_group_engine(int thread_id);

private:
    std::map<int, GroupEngine*>* group_engines;
};
